package sf.database.jdbc.sql;

import sf.common.wrapper.Page;
import sf.database.OrmContext;
import sf.database.OrmParameter;
import sf.database.dao.DBContext;
import sf.database.dialect.DBDialect;
import sf.database.util.DBUtils;
import sf.dsl.Example;
import sf.dsl.ExampleSQLHelp;

import java.sql.Connection;
import java.util.List;
import java.util.Map;

/**
 * 按example操作
 */
public class CrudExampleImpl implements CrudExampleInf {

    @Override
    public <T> Page<T> selectPage(Connection conn, long start, int limit, Class<T> beanClass, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, false, example.isCount(), false);
        return Crud.getInstance().getCrudModel().selectPage(conn, start, limit, beanClass, select);
    }

    @Override
    public Object[] selectArray(Connection conn, Example example) {
        return selectOne(conn, Object[].class, example);
    }

    @Override
    public <T> List<T> selectList(Connection conn, Class<T> beanClass, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, false, example.isCount());
        return Crud.getInstance().getCrudModel().selectList(conn, beanClass, select);
    }

    @Override
    public <T> List<T> selectList(Connection conn, Class<T> beanClass, long start, int limit, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, false, example.isCount(), false);
        return Crud.getInstance().getCrudModel().selectList(conn, beanClass, select, start, limit);
    }

    @Override
    public <T> List<T> selectListForUpdate(Connection conn, Class<T> beanClass, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, true, example.isCount());
        return Crud.getInstance().getCrudModel().selectList(conn, beanClass, select);
    }

    @Override
    public <T> T selectOne(Connection conn, Class<T> beanClass, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, false, example.isCount());
        return Crud.getInstance().getCrudModel().selectOne(conn, beanClass, select);
    }

    @Override
    public <T> T selectOneForUpdate(Connection conn, Class<T> beanClass, Example example) {
        DBDialect dialect = DBUtils.doGetDialect(conn, false);
        DBContext DBContext = DBUtils.doGetDBContext(conn);
        OrmContext select = getQuerySelect(DBContext, dialect, example, true, example.isCount());
        return Crud.getInstance().getCrudModel().selectOne(conn, beanClass, select);
    }

    @Override
    public List<Map<String, Object>> select(Connection conn, Example example) {
        return (List<Map<String, Object>>) selectOne(conn, Map.class, example);
    }

    /**
     * @param context
     * @param dialect
     * @param query
     * @param forUpdate
     * @param count
     * @return
     */
    private OrmContext getQuerySelect(DBContext context, DBDialect dialect, Example query, boolean forUpdate, boolean count) {
        return getQuerySelect(context, dialect, query, forUpdate, count, true);//默认使用example中的分页参数
    }

    /**
     * @param context
     * @param dialect
     * @param example     查询条件
     * @param forUpdate   是否需要加入 for update
     * @param count       是否统计总数
     * @param offsetLimit 是否使用Example中的offsetLimit
     * @return
     */
    private OrmContext getQuerySelect(DBContext context, DBDialect dialect, Example example, boolean forUpdate, boolean count, boolean offsetLimit) {
        OrmContext ctx = new OrmContext();
        StringBuilder sql = new StringBuilder();

        example.setDialect(dialect);
        OrmContext sub = ExampleSQLHelp.getSelectOrmContext(example, context, count, offsetLimit, true);
        sql.append(sub.getSql());
        List<OrmParameter> list = sub.getParas();

        if (forUpdate) {
            sql.append(" for update");
        }
        ctx.setSql(sql.toString());
        ctx.setParas(list);
        return ctx;
    }
}
